#include "../exercise.h"

// READ: 静态字段 <https://zh.cppreference.com/w/cpp/language/static>
// READ: 虚析构函数 <https://zh.cppreference.com/w/cpp/language/destructor>

struct A {
    // TODO: 正确初始化静态字段
    static int num_a;

    A() {
        ++num_a;
    }
    // ~A() {
    //     --num_a;
    // }
    // 为什么要改成虚析构函数
    // 因为析构会出错

    // 添加虚析构函数
    virtual ~A() {
        --num_a;
    }

    virtual char name() const {
        return 'A';
    }
};

// 静态字段在类外定义和初始化
int A::num_a = 0;


struct B final : public A {
    // TODO: 正确初始化静态字段
    static int num_b;

    B() {
        ++num_b;
    }
    ~B() {
        --num_b;
    }

    char name() const final {
        return 'B';
    }
};

// 静态字段在类外定义和初始化
int B::num_b = 0;



int main(int argc, char **argv) {
    auto a = new A;
    auto b = new B;
    ASSERT(A::num_a == 2, "Fill in the correct value for A::num_a");
    ASSERT(B::num_b == 1, "Fill in the correct value for B::num_b");
    ASSERT(a->name() == 'A', "Fill in the correct value for a->name()");
    ASSERT(b->name() == 'B', "Fill in the correct value for b->name()");

    delete a;
    delete b;
    ASSERT(A::num_a == 0, "Every A was destroyed");
    ASSERT(B::num_b == 0, "Every B was destroyed");

    A *ab = new B;// 派生类指针可以随意转换为基类指针
    ASSERT(A::num_a == 1, "Fill in the correct value for A::num_a");
    ASSERT(B::num_b == 1, "Fill in the correct value for B::num_b");
    ASSERT(ab->name() == 'B', "Fill in the correct value for ab->name()");

    // TODO: 基类指针无法随意转换为派生类指针，补全正确的转换语句
    // B &bb = *ab;
    // 基类指针无法随意转换为派生类指针，使用dynamic_cast进行安全的向下转型
    // B *bb_ptr = dynamic_cast<B*>(ab);
    // ASSERT(bb_ptr != nullptr, "Dynamic cast should succeed");
    // ASSERT(bb_ptr->name() == 'B', "Fill in the correct value for bb->name()");
    
    
    B &bb = *dynamic_cast<B*>(ab);
    ASSERT(bb.name() == 'B', "Fill in the correct value for bb->name()");

    // TODO: ---- 以下代码不要修改，通过改正类定义解决编译问题 ----
    delete ab;// 通过指针可以删除指向的对象，即使是多态对象
    ASSERT(A::num_a == 0, "Every A was destroyed");
    ASSERT(B::num_b == 0, "Every B was destroyed");

    return 0;
}


/*
有虚函数，就有虚析构函数

静态字段，属于这个类，不属于具体的某个类对象


ok：静态字段，要类外初始化

虚析构函数！

静态字段初始化：静态字段需要在类外单独初始化
虚析构函数：多态基类需要虚析构函数来确保正确析构
向下转型：需要使用dynamic_cast进行安全的向下转型

关键修正解释
1. 静态字段初始化
// 类内声明
static int num_a;

// 类外定义和初始化
int A::num_a = 0;
静态字段需要在类外单独定义和初始化，这是C++的语法要求。

2. 虚析构函数
virtual ~A() {
    --num_a;
}
为什么需要虚析构函数？

当通过基类指针删除派生类对象时，如果析构函数不是虚的，只会调用基类的析构函数
派生类的析构函数不会被调用，导致资源泄漏
虚析构函数确保正确的析构顺序：先派生类后基类
3. 安全的向下转型
B *bb_ptr = dynamic_cast<B*>(ab);
dynamic_cast在运行时检查类型转换是否安全
如果转换失败（类型不匹配），返回nullptr
比C风格转换(B*)ab更安全
4. 对象计数逻辑
A *ab = new B;
// A::num_a == 1 (B继承自A，所以构造B时也会构造A)
// B::num_b == 1 (B对象本身)
由于B继承自A，创建B对象时：

先调用A的构造函数：A::num_a++
再调用B的构造函数：B::num_b++
测试验证
程序运行后会通过所有断言：

对象计数正确
多态调用正确（ab->name()返回'B'）
析构正确（通过虚析构函数确保完整清理）
向下转型安全
重要经验
多态基类必须有虚析构函数：这是C++的重要最佳实践
静态成员需要类外定义：这是语法要求
使用dynamic_cast进行向下转型：比C风格转换更安全
理解对象构造/析构顺序：对于继承体系很重要
这个修正确保了代码的正确性和安全性，特别是避免了多态对象删除时的资源泄漏问题。




上一题：
#include "../exercise.h"

// READ: 虚函数 <https://zh.cppreference.com/w/cpp/language/virtual>

struct A {
    virtual char virtual_name() const {
        return 'A';
    }
    char direct_name() const {
        return 'A';
    }
};
struct B : public A {
    // READ: override <https://zh.cppreference.com/w/cpp/language/override>
    char virtual_name() const override {
        return 'B';
    }
    char direct_name() const {
        return 'B';
    }
};
struct C : public B {
    // READ: final <https://zh.cppreference.com/w/cpp/language/final>
    char virtual_name() const final {
        return 'C';
    }
    char direct_name() const {
        return 'C';
    }
};
struct D : public C {
    char direct_name() const {
        return 'D';
    }
    // virtual_name() 没有重写，使用C的final版本
};
*/
